﻿Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.Activities
    Friend Class StateMachineDesignerPaint
        ' Methods
        Private Shared Sub AddRoundedCorner(ByVal path As GraphicsPath, ByVal diameter As Integer, ByVal midPoint As Point, ByVal direction1 As ArrowDirection, ByVal direction2 As ArrowDirection)
            Select Case direction1
                Case ArrowDirection.Left
                    If (direction2 <> ArrowDirection.Down) Then
                        path.AddArc(midPoint.X, (midPoint.Y - diameter), diameter, diameter, 90!, 90!)
                        Return
                    End If
                    path.AddArc(midPoint.X, midPoint.Y, diameter, diameter, 270!, -90!)
                    Return
                Case ArrowDirection.Up
                    If (direction2 <> ArrowDirection.Left) Then
                        path.AddArc(midPoint.X, midPoint.Y, diameter, diameter, 180!, 90!)
                        Return
                    End If
                    path.AddArc((midPoint.X - diameter), midPoint.Y, diameter, diameter, 0!, -90!)
                    Return
                Case ArrowDirection.Right
                    If (direction2 = ArrowDirection.Down) Then
                        path.AddArc((midPoint.X - diameter), midPoint.Y, diameter, diameter, 270!, 90!)
                        Return
                    End If
                    path.AddArc((midPoint.X - diameter), (midPoint.Y - diameter), diameter, diameter, 90!, -90!)
                    Return
            End Select
            If (direction2 = ArrowDirection.Left) Then
                path.AddArc((midPoint.X - diameter), (midPoint.Y - diameter), diameter, diameter, 0!, 90!)
            Else
                path.AddArc(midPoint.X, (midPoint.Y - diameter), diameter, diameter, 180!, -90!)
            End If
        End Sub

        Private Shared Sub AddSegment(ByVal path As GraphicsPath, ByVal radius As Integer, ByVal p1 As Point, ByVal p2 As Point, ByVal roundP1 As Boolean, ByVal roundP2 As Boolean, ByVal direction As ArrowDirection)
            If roundP1 Then
                Select Case direction
                    Case ArrowDirection.Left
                        p1.X = (p1.X - radius)
                        goto Label_005C
                    Case ArrowDirection.Up
                        p1.Y = (p1.Y - radius)
                        goto Label_005C
                    Case ArrowDirection.Down
                        p1.Y = (p1.Y + radius)
                        goto Label_005C
                End Select
                p1.X = (p1.X + radius)
            End If
        Label_005C:
            If roundP2 Then
                Select Case direction
                    Case ArrowDirection.Left
                        p2.X = (p2.X + radius)
                        goto Label_00B8
                    Case ArrowDirection.Up
                        p2.Y = (p2.Y + radius)
                        goto Label_00B8
                    Case ArrowDirection.Down
                        p2.Y = (p2.Y - radius)
                        goto Label_00B8
                End Select
                p2.X = (p2.X - radius)
            End If
        Label_00B8:
            path.AddLine(p1, p2)
        End Sub

        Friend Shared Sub DrawConnector(ByVal graphics As Graphics, ByVal pen As Pen, ByVal points As Point(), ByVal connectorCapSize As Size, ByVal maxCapSize As Size, ByVal startConnectorCap As LineAnchor, ByVal endConnectorCap As LineAnchor)
            If (points.GetLength(0) >= 2) Then
                points = StateMachineDesignerPaint.OptimizeConnectorPoints(points)
                Dim path As GraphicsPath = Nothing
                Dim capinset As Single = 0!
                If (startConnectorCap <> LineAnchor.None) Then
                    Dim pointArray As Point() = New Point() { points(0), points(1) }
                    Dim num2 As Integer = If((pointArray(0).Y = pointArray(1).Y), connectorCapSize.Width, connectorCapSize.Height)
                    num2 = (num2 + (num2 Mod 2))
                    num2 = Math.Min(Math.Min(num2, maxCapSize.Width), maxCapSize.Height)
                    path = StateMachineDesignerPaint.GetLineCap(startConnectorCap, num2, capinset)
                    If (((Not path Is Nothing) AndAlso ((startConnectorCap Mod LineAnchor.ArrowAnchor) = LineAnchor.None)) AndAlso ((pointArray(0).X = pointArray(1).X) OrElse (pointArray(0).Y = pointArray(1).Y))) Then
                        Dim transform As Matrix = graphics.Transform
                        graphics.TranslateTransform(CSng(pointArray(0).X), CSng(pointArray(0).Y))
                        If (pointArray(0).Y = pointArray(1).Y) Then
                            graphics.RotateTransform(If((pointArray(0).X < pointArray(1).X), 90!, 270!))
                        Else
                            graphics.RotateTransform(If((pointArray(0).Y < pointArray(1).Y), 180!, 0!))
                        End If
                        [Using] brush As Brush = New SolidBrush(pen.Color)
                            graphics.FillPath(brush, path)
                        End [Using]
                        graphics.Transform = If((Not transform Is Nothing), transform, New Matrix)
                    End If
                End If
                Dim path2 As GraphicsPath = Nothing
                Dim num3 As Single = 0!
                If (endConnectorCap <> LineAnchor.None) Then
                    Dim pointArray2 As Point() = New Point() { points((points.GetLength(0) - 2)), points((points.GetLength(0) - 1)) }
                    Dim num4 As Integer = If((pointArray2(0).Y = pointArray2(1).Y), connectorCapSize.Width, connectorCapSize.Height)
                    num4 = (num4 + (num4 Mod 2))
                    num4 = Math.Min(Math.Min(num4, maxCapSize.Width), maxCapSize.Height)
                    path2 = StateMachineDesignerPaint.GetLineCap(endConnectorCap, num4, num3)
                    If (((Not path2 Is Nothing) AndAlso ((endConnectorCap Mod LineAnchor.ArrowAnchor) = LineAnchor.None)) AndAlso ((pointArray2(0).X = pointArray2(1).X) OrElse (pointArray2(0).Y = pointArray2(1).Y))) Then
                        Dim matrix2 As Matrix = graphics.Transform
                        graphics.TranslateTransform(CSng(pointArray2(1).X), CSng(pointArray2(1).Y))
                        If (pointArray2(0).Y = pointArray2(1).Y) Then
                            graphics.RotateTransform(If((pointArray2(0).X < pointArray2(1).X), 270!, 90!))
                        Else
                            graphics.RotateTransform(If((pointArray2(0).Y < pointArray2(1).Y), 0!, 180!))
                        End If
                        [Using] brush2 As Brush = New SolidBrush(pen.Color)
                            graphics.FillPath(brush2, path2)
                        End [Using]
                        graphics.Transform = If((Not matrix2 Is Nothing), matrix2, New Matrix)
                    End If
                End If
                If (Not path Is Nothing) Then
                    Dim cap As New CustomLineCap(Nothing, path) { _
                        .WidthScale = (1! / pen.Width), _
                        .BaseInset = capinset _
                    }
                    pen.CustomStartCap = cap
                End If
                If (Not path2 Is Nothing) Then
                    Dim cap2 As New CustomLineCap(Nothing, path2) { _
                        .WidthScale = (1! / pen.Width), _
                        .BaseInset = num3 _
                    }
                    pen.CustomEndCap = cap2
                End If
                [Using] path3 As GraphicsPath = StateMachineDesignerPaint.GetRoundedPath(points, 5)
                    graphics.DrawPath(pen, path3)
                End [Using]
                If (Not path Is Nothing) Then
                    Dim customStartCap As CustomLineCap = pen.CustomStartCap
                    pen.StartCap = LineCap.Flat
                    customStartCap.Dispose
                End If
                If (Not path2 Is Nothing) Then
                    Dim customEndCap As CustomLineCap = pen.CustomEndCap
                    pen.EndCap = LineCap.Flat
                    customEndCap.Dispose
                End If
            End If
        End Sub

        Friend Shared Function GetDesignerPath(ByVal designer As ActivityDesigner, ByVal bounds As Rectangle, ByVal designerTheme As ActivityDesignerTheme) As GraphicsPath
            Dim path As New GraphicsPath
            If ((designer Is StateMachineDesignerPaint.GetSafeRootDesigner(designer.Activity.Site)) AndAlso (DirectCast(designer, IWorkflowRootDesigner).InvokingDesigner Is Nothing)) Then
                path.AddRectangle(bounds)
                Return path
            End If
            Dim radius As Integer = 8
            If ((Not designerTheme Is Nothing) AndAlso (designerTheme.DesignerGeometry = DesignerGeometry.RoundedRectangle)) Then
                path.AddPath(ActivityDesignerPaint.GetRoundedRectanglePath(bounds, radius), True)
                Return path
            End If
            path.AddRectangle(bounds)
            Return path
        End Function

        Private Shared Function GetDirection(ByVal start As Point, ByVal [end] As Point) As ArrowDirection
            If (start.X = [end].X) Then
                If (start.Y < [end].Y) Then
                    Return ArrowDirection.Down
                End If
                Return ArrowDirection.Up
            End If
            If (start.X < [end].X) Then
                Return ArrowDirection.Right
            End If
            Return ArrowDirection.Left
        End Function

        Private Shared Function GetDistance(ByVal p1 As Point, ByVal p2 As Point) As Integer
            If (p1.X = p2.X) Then
                Return Math.Abs(CInt((p1.Y - p2.Y)))
            End If
            Return Math.Abs(CInt((p1.X - p2.X)))
        End Function

        Friend Shared Function GetLineCap(ByVal lineCap As LineAnchor, ByVal capsize As Integer, <Out> ByRef capinset As Single) As GraphicsPath
            Dim num As Integer
            capinset = 0!
            capinset = (CSng(capsize) / 2!)
            Dim size As New Size(capsize, capsize)
            Dim path As New GraphicsPath
            Select Case lineCap
                Case LineAnchor.Arrow, LineAnchor.ArrowAnchor
                    num = (size.Height / 3)
                    path.AddLine((size.Width / 2), -size.Height, 0, 0)
                    path.AddLine(0, 0, (-size.Width / 2), -size.Height)
                    path.AddLine((-size.Width / 2), -size.Height, 0, (-size.Height + num))
                    path.AddLine(0, (-size.Height + num), (size.Width / 2), -size.Height)
                    capinset = (size.Height - num)
                    Exit Select
                Case LineAnchor.Diamond, LineAnchor.DiamondAnchor
                    path.AddLine(0, -size.Height, (size.Width / 2), (-size.Height / 2))
                    path.AddLine((size.Width / 2), (-size.Height / 2), 0, 0)
                    path.AddLine(0, 0, (-size.Width / 2), (-size.Height / 2))
                    path.AddLine((-size.Width / 2), (-size.Height / 2), 0, -size.Height)
                    Exit Select
                Case LineAnchor.Round, LineAnchor.RoundAnchor
                    path.AddEllipse(New Rectangle((-size.Width / 2), -size.Height, size.Width, size.Height))
                    Exit Select
                Case LineAnchor.Rectangle, LineAnchor.RectangleAnchor
                    path.AddRectangle(New Rectangle((-size.Width / 2), -size.Height, size.Width, size.Height))
                    Exit Select
                Case LineAnchor.RoundedRectangle, LineAnchor.RoundedRectangleAnchor
                    num = (size.Height / 4)
                    path.AddPath(ActivityDesignerPaint.GetRoundedRectanglePath(New Rectangle((-size.Width / 2), -size.Height, size.Width, size.Height), num), True)
                    Exit Select
            End Select
            path.CloseFigure
            Return path
        End Function

        Private Shared Function GetRoundedPath(ByVal points As Point(), ByVal radius As Integer) As GraphicsPath
            Dim path As New GraphicsPath
            If (points.Length = 2) Then
                path.AddLine(points(0), points(1))
                Return path
            End If
            Dim diameter As Integer = (radius * 2)
            Dim point As Point = points(0)
            Dim point2 As Point = points(1)
            Dim point3 As Point = points(2)
            Dim distance As Integer = StateMachineDesignerPaint.GetDistance(point, point2)
            Dim num4 As Integer = StateMachineDesignerPaint.GetDistance(point2, point3)
            Dim direction As ArrowDirection = StateMachineDesignerPaint.GetDirection(point, point2)
            Dim direction2 As ArrowDirection = StateMachineDesignerPaint.GetDirection(point2, point3)
            If ((distance < diameter) OrElse (num4 < diameter)) Then
                StateMachineDesignerPaint.AddSegment(path, radius, point, point2, False, False, direction)
            Else
                StateMachineDesignerPaint.AddSegment(path, radius, point, point2, False, True, direction)
                StateMachineDesignerPaint.AddRoundedCorner(path, diameter, point2, direction, direction2)
            End If
            Dim i As Integer
            For i = 2 To (points.Length - 1) - 1
                Dim num2 As Integer = distance
                distance = num4
                direction = direction2
                point = point2
                point2 = point3
                point3 = points((i + 1))
                direction2 = StateMachineDesignerPaint.GetDirection(point2, point3)
                num4 = StateMachineDesignerPaint.GetDistance(point2, point3)
                If ((distance >= diameter) AndAlso (num4 >= diameter)) Then
                    StateMachineDesignerPaint.AddSegment(path, radius, point, point2, (num2 >= diameter), True, direction)
                    StateMachineDesignerPaint.AddRoundedCorner(path, diameter, point2, direction, direction2)
                Else
                    StateMachineDesignerPaint.AddSegment(path, radius, point, point2, (num2 >= diameter), False, direction)
                End If
            Next i
            StateMachineDesignerPaint.AddSegment(path, radius, point2, point3, ((distance >= diameter) AndAlso (num4 >= diameter)), False, direction2)
            Return path
        End Function

        Friend Shared Function GetSafeRootDesigner(ByVal serviceProvider As IServiceProvider) As ActivityDesigner
            If (serviceProvider Is Nothing) Then
                Return Nothing
            End If
            Return ActivityDesigner.GetRootDesigner(serviceProvider)
        End Function

        Friend Shared Function MeasureString(ByVal graphics As Graphics, ByVal font As Font, ByVal [text] As String, ByVal alignment As StringAlignment, ByVal maxSize As Size) As Size
            Dim empty As SizeF = SizeF.Empty
            If maxSize.IsEmpty Then
                empty = graphics.MeasureString([text], font)
            Else
                Dim stringFormat As New StringFormat { _
                    .Alignment = alignment, _
                    .LineAlignment = StringAlignment.Center, _
                    .Trimming = StringTrimming.EllipsisCharacter, _
                    .FormatFlags = StringFormatFlags.LineLimit _
                }
                empty = graphics.MeasureString([text], font, New SizeF(CSng(maxSize.Width), CSng(maxSize.Height)), stringFormat)
            End If
            Return New Size(Convert.ToInt32(Math.Ceiling(CDbl(empty.Width))), Convert.ToInt32(Math.Ceiling(CDbl(empty.Height))))
        End Function

        Private Shared Function OptimizeConnectorPoints(ByVal points As Point()) As Point()
            Dim list As New List([Of] Point) { points(0) }
            Dim item As Point = points(0)
            Dim point3 As Point = points(1)
            If ((item.X <> point3.X) AndAlso (item.Y <> point3.Y)) Then
                list.Add(New Point(point3.X, item.Y))
            End If
            Dim i As Integer
            For i = 2 To points.Length - 1
                Dim point As Point = item
                item = point3
                point3 = points(i)
                If (((point.X <> item.X) OrElse (item.X <> point3.X)) AndAlso ((point.Y <> item.Y) OrElse (item.Y <> point3.Y))) Then
                    list.Add(item)
                    If ((item.X <> point3.X) AndAlso (item.Y <> point3.Y)) Then
                        list.Add(New Point(point3.X, item.Y))
                    End If
                End If
            Next i
            list.Add(points((points.Length - 1)))
            Return list.ToArray
        End Function

        Friend Shared Function TrimRectangle(ByVal rectangle As Rectangle, ByVal bounds As Rectangle) As Rectangle
            Dim left As Integer = rectangle.Left
            Dim top As Integer = rectangle.Top
            Dim width As Integer = rectangle.Width
            Dim height As Integer = rectangle.Height
            If (left < bounds.Left) Then
                left = bounds.Left
            End If
            If (top < bounds.Top) Then
                top = bounds.Top
            End If
            If ((left + width) > bounds.Right) Then
                width = (width - (rectangle.Right - bounds.Right))
            End If
            If ((top + height) > bounds.Bottom) Then
                height = (height - (rectangle.Bottom - bounds.Bottom))
            End If
            Return New Rectangle(left, top, width, height)
        End Function


        ' Fields
        Friend Shared ReadOnly FadeBrush As Brush = New SolidBrush(Color.FromArgb(120, &HFF, &HFF, &HFF))
    End Class
End Namespace

